﻿using Haidou.Wpf.Util.Settings;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Markup;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
namespace Haidou.Wpf.Util
{
	/// <summary>
	/// 处理本地化行为。 查找本地化字符串 
	/// </summary>
	public static class LocalizationHelper
	{
		public static string CurrentCulture { get; set; }

		public static CultureInfo CurrentCultureInfo { get; set; }

		/// <summary>
		/// 选择  文化 语言
		/// </summary>
		/// <param name="culture"></param>
		public static void SelectCulture(string culture)
		{
			CurrentCultureInfo ??= CultureInfo.CurrentUICulture;//获取系统语言 zh-CN


			#region Validation

			//如果没有选择，退回到中文。
			if (string.IsNullOrEmpty(culture))
			{
				culture = "zh";
			}

			if (culture.Equals("auto") || culture.Length < 2)
			{
				culture = CurrentCultureInfo.Name;
			}

			#endregion

			//将所有合并目录复制到一个辅助列表中。
			List<ResourceDictionary> dictionaryList = Application.Current.Resources.MergedDictionaries.ToList();

			#region Selected Culture

			//搜索指定的区域性。
			string requestedCulture = $"/Resources/Localization/StringResources.{culture}.xaml";
			ResourceDictionary? requestedResource = dictionaryList.FirstOrDefault(d => d.Source?.OriginalString == requestedCulture);

			#endregion

			#region Generic Branch Fallback

			//退回到更通用的语言版本。例如:pt-BR到pt。
			while (requestedResource == null && !string.IsNullOrEmpty(culture))
			{
				culture = CultureInfo.GetCultureInfo(culture).Parent.Name;
				requestedCulture = $"/Resources/Localization/StringResources.{culture}.xaml";
				requestedResource = dictionaryList.FirstOrDefault(d => d.Source?.OriginalString == requestedCulture);
			}

			#endregion

			#region zh Fallback

			//如果不存在，退回到中文。
			if (requestedResource == null)
			{
				culture = "zh";
				requestedCulture = "/Resources/Localization/StringResources.zh.xaml";
				requestedResource = dictionaryList.FirstOrDefault(d => d.Source?.OriginalString == requestedCulture);
			}

			#endregion

			//如果我们有请求的资源，从列表中删除它并放在最后。
			//那么这个语言就是我们现在的字符串表
			Application.Current.Resources.MergedDictionaries.Remove(requestedResource);
			//Application.Current.Resources.MergedDictionaries.Add(requestedResource);

			CurrentCulture = culture;

			//告知新文化的线索。
			CultureInfo.CurrentCulture = new CultureInfo(culture);
			CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture;
			CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CurrentCulture;
			CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CurrentCulture;

			#region English Fallback of the Current Language

			//只有非中文资源需要后备，因为中文资源是常用
			if (culture.StartsWith("zh"))
			{
				return;
			}

			ResourceDictionary? englishResource = dictionaryList.FirstOrDefault(d => d.Source?.OriginalString == "/Resources/Localization/StringResources.zh.xaml");

			if (englishResource != null)
			{
				Application.Current.Resources.MergedDictionaries.Remove(englishResource);
				Application.Current.Resources.MergedDictionaries.Insert(Application.Current.Resources.MergedDictionaries.Count - 1, englishResource);
			}

			#endregion

			GC.Collect(0);

			if (!UserSettings.All.CheckForTranslationUpdates)
			{
				return;
			}

			//异步，文件
			//Task.Factory.StartNew(() => CheckForUpdates(culture));//不检查翻译资源更新
		}

		/// <summary>
		/// This is what happens:
		///
		///获取可用资源的日期
		///如果可用资源比程序集新
		///如果已经下载了翻译
		///如果当前翻译版本比可用版本旧
		///下载最新版本，覆盖当前版本
		///如果当前翻译较新
		///不要下载
		///如果还没有下载翻译
		///下载最新版本
		///如果可用资源比程序集旧
		///不下载，清除当前翻译
		/// </summary>
		/// <param name="culture">应该在其中搜索更新的区域性。</param>
		internal static void CheckForUpdates(string culture)
		{
			try
			{
				if (string.IsNullOrWhiteSpace(UserSettings.All.TemporaryFolderResolved))
				{
					return;
				}

				string folder = Path.Combine(UserSettings.All.TemporaryFolderResolved, "AI Hub", "Localization");
				string file = Path.Combine(folder, $"StringResources.{culture}.new.xaml");

				Directory.CreateDirectory(folder);

				//获取可用资源的更新时间。
				//var updated = GetWhenResourceWasUpdated(culture);// 不用服务器资源
				DateTime? updated = new DateTime?();
				//如果可用资源比程序集旧。  不比较去掉了 !
				if (updated.HasValue || updated <= File.GetLastWriteTime(ProcessHelper.GetEntryAssemblyPath()))
				{
					if (File.Exists(file))
					{
						File.Delete(file);
					}

					return;
				}

				//如果先前下载了翻译。
				if (File.Exists(file))
				{
					//如果当前翻译版本比可用版本旧。
					if (new FileInfo(file).LastWriteTimeUtc < updated.Value.ToUniversalTime())
					{

					}
					//DownloadLatest(file, culture);//不下载
				}
				else
				{
					//DownloadLatest(file, culture);
				}

				//如果没有下载新的翻译(现在或以前)，忽略下面的代码。  //更新 去掉了!
				if (!File.Exists(file))
				{
					return;
				}

				//删除此更新程序添加的任何资源。
				List<ResourceDictionary> listToRemove = Application.Current.Resources.MergedDictionaries.Where(w => w.Source?.OriginalString.EndsWith(".new.xaml") == true).ToList();

				foreach (ResourceDictionary? rem in listToRemove)
				{
					Application.Current.Resources.MergedDictionaries.Remove(rem);
				}

				//从文件中加载资源，不替换当前资源，而是放在它后面。
				using FileStream fs = new(file, FileMode.Open, FileAccess.Read, FileShare.Read);

				if (fs.Length == 0)
				{
					throw new InvalidDataException("File is empty");
				}

				//读取资源字典文件
				ResourceDictionary dictionary = (ResourceDictionary)XamlReader.Load(fs);
				dictionary.Source = new Uri(Path.Combine(file));

				//添加新加载的资源字典。
				Application.Current.Resources.MergedDictionaries.Add(dictionary);
			}
			catch (WebException)
			{
				//忽略它。
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Check for an updated localization resource");
			}
		}

		/// <summary>
		/// Checks when the available resource file was updated.检查可用资源文件的更新时间。
		/// </summary>
		/// <param name="culture">The culture of the resource to be checked.要检查的资源的区域性。</param>
		/// <returns>The date when the resource file was last updated.上次更新资源文件的日期</returns>
		private static DateTime? GetWhenResourceWasUpdated(string culture)
		{
			//Gets the latest commit that changed the translation resource. 获取更改翻译资源的最新提交。
			HttpWebRequest req = (HttpWebRequest)WebRequest.Create($"https://api.github.com/repos/NickeManarin/Haidou.Wpf.UI/commits?path=Haidou.Wpf.UI/Resources/Localization/StringResources.{culture}.xaml&page=1&per_page=1");
			req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393";
			req.Proxy = WebHelper.GetProxy();

			HttpWebResponse res = (HttpWebResponse)req.GetResponse();

			using Stream resultStream = res.GetResponseStream();
			using StreamReader reader = new(resultStream);

			string result = reader.ReadToEnd();
			XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(result), new XmlDictionaryReaderQuotas());
			XElement release = XElement.Load(jsonReader);

			//Gets the date of of the last commit that changed the translation file./获取更改翻译文件的最后一次提交的日期。
			string? dateText = release.FirstNode.XPathSelectElement("commit")?.XPathSelectElement("committer")?.XPathSelectElement("date")?.Value;

			//If was not possible to convert the time, keep using the current resource.如果无法转换时间，请继续使用当前资源。
			if (!DateTime.TryParse(dateText, out DateTime modificationDate))
			{
				return null;
			}

			//If the current resource is newer then the available one, keep using the current.如果当前资源比可用资源新，则继续使用当前资源。
			return modificationDate;
		}

		/// <summary>
		/// Downloads the available localization resource.下载可用的本地化资源。
		/// </summary>
		/// <param name="file">The destination path of the resource.资源的目标路径。</param>
		/// <param name="culture">The culture of the resource to be downloaded.要下载的资源的区域性</param>
		private static void DownloadLatest(string file, string culture)
		{
			HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"https://api.github.com/repos/NickeManarin/Haidou.Wpf.UI/contents/Haidou.Wpf.UI/Resources/Localization/StringResources.{culture}.xaml");
			request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393";
			request.Proxy = WebHelper.GetProxy();

			HttpWebResponse response = (HttpWebResponse)request.GetResponse();

			using Stream resultStream = response.GetResponseStream();
			using StreamReader reader = new(resultStream);

			string result = reader.ReadToEnd();
			XmlDictionaryReader jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(result), new XmlDictionaryReaderQuotas());
			XElement release = XElement.Load(jsonReader);

			//When creating a GET request with a direct path, the 'content' element is available as a base64 string.当使用直接路径创建GET请求时，“content”元素作为base64字符串可用。
			string? contentBase64 = release.XPathSelectElement("content")?.Value;

			if (string.IsNullOrWhiteSpace(contentBase64))
			{
				return;
			}

			if (File.Exists(file))
			{
				File.Delete(file);
			}

			File.WriteAllText(file, Encoding.UTF8.GetString(Convert.FromBase64String(contentBase64)).Replace("&#x0d;", "\r"));
		}

		/// <summary>
		/// 保存默认资源
		/// </summary>
		/// <param name="path"></param>
		public static void SaveDefaultResource(string path)
		{
			//将所有MergedDictionaries复制到一个辅助列表中
			List<ResourceDictionary> dictionaryList = Application.Current.Resources.MergedDictionaries.ToList();

			try
			{
				//搜索指定的区域性。
				ResourceDictionary? resourceDictionary = dictionaryList.FirstOrDefault(d => d.Source?.OriginalString == "/Resources/Localization/StringResources.en.xaml");

				if (resourceDictionary == null)
				{
					throw new CultureNotFoundException("String resource not found.");
				}

				if (string.IsNullOrEmpty(path))
				{
					throw new ArgumentException("Path is null.");
				}

				XmlWriterSettings settings = new() { Indent = true };

				using (XmlWriter writer = XmlWriter.Create(path, settings))
				{
					XamlWriter.Save(resourceDictionary, writer);
				}
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Save Xaml Resource Error");

				throw;
			}
		}

		/// <summary>
		/// 导入字符串资源
		/// </summary>
		/// <param name="path"></param>
		public static void ImportStringResource(string path)
		{
			try
			{
				if (string.IsNullOrEmpty(path))
				{
					throw new ArgumentException("Path is null");
				}

				string destination = Path.Combine(Path.GetTempPath(), Path.GetFileName(path));

				if (File.Exists(destination))
				{
					File.Delete(destination);
				}

				File.WriteAllText(destination, File.ReadAllText(path).Replace("&#x0d;", "\r"));

				using FileStream fs = new(destination, FileMode.Open, FileAccess.Read, FileShare.Read);

				if (fs.Length == 0)
				{
					throw new InvalidDataException("File is empty");
				}

				//Reads the ResourceDictionary file 读取资源字典文件
				ResourceDictionary dictionary = (ResourceDictionary)XamlReader.Load(fs);
				dictionary.Source = new Uri(destination);

				//Add in newly loaded Resource Dictionary.添加新加载的资源字典。
				Application.Current.Resources.MergedDictionaries.Add(dictionary);
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Import Resource");
				//Rethrowing, because it's more useful to catch later。 重新抛出，因为稍后捕捉更有用
				throw;
			}
		}

		public static List<ResourceDictionary> GetLocalizations()
		{
			//Copy all MergedDictionaries into a auxiliary list.将所有合并目录复制到一个辅助列表中。
			List<ResourceDictionary> dictionaryList = Application.Current.Resources.MergedDictionaries.ToList();

			return dictionaryList.Where(x => x.Source.OriginalString.Contains("StringResource")).ToList();
		}

		public static bool Move(int selectedIndex, bool toUp = true)
		{
			try
			{
				if (toUp && selectedIndex < 1)
				{
					return false;
				}

				if (!toUp && selectedIndex > Application.Current.Resources.MergedDictionaries.Count - 1)
				{
					return false;
				}

				//Recover the selected dictionary.恢复选定的字典。
				ResourceDictionary dictionaryAux = Application.Current.Resources.MergedDictionaries[selectedIndex];

				//Remove from the current list.从当前列表中删除。
				Application.Current.Resources.MergedDictionaries.Remove(Application.Current.Resources.MergedDictionaries[selectedIndex]);

				//Detect the index of the next localization.检测下一个定位的索引。
				int newIndex = -1;

				if (toUp)
				{
					//Search for the index of the previous localization resource.搜索以前本地化资源的索引。
					for (int i = selectedIndex - 1; i >= 0; i--)
					{
						if (Application.Current.Resources.MergedDictionaries[i].Source?.OriginalString?.Contains("StringResources") == true)
						{
							newIndex = i;
							break;
						}
					}
				}
				else
				{
					//Search for the index of the next localization resource.搜索下一个本地化资源的索引。
					for (int i = selectedIndex; i < Application.Current.Resources.MergedDictionaries.Count; i++)
					{
						if (Application.Current.Resources.MergedDictionaries[i].Source?.OriginalString?.Contains("StringResources") == true)
						{
							newIndex = i + 1;
							break;
						}
					}
				}

				//Insert at the new position.在新位置插入。
				Application.Current.Resources.MergedDictionaries.Insert(newIndex, dictionaryAux);

				return true;
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Move Resource", selectedIndex);
				return false;
			}
		}

		public static void SaveSelected(int selectedIndex, string path)
		{
			try
			{
				if (selectedIndex < 0 || selectedIndex > Application.Current.Resources.MergedDictionaries.Count - 1)
				{
					throw new IndexOutOfRangeException("Index out of range while trying to save the resource dictionary.");
				}

				XmlWriterSettings settings = new() { Indent = true };

				using XmlWriter writer = XmlWriter.Create(path, settings);
				XamlWriter.Save(Application.Current.Resources.MergedDictionaries[selectedIndex], writer);
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Save Resource", selectedIndex);
				//Rethrowing, because it's more useful to catch later   重新抛出，因为稍后捕捉更有用
				throw;
			}
		}

		public static bool Remove(int selectedIndex)
		{
			try
			{
				if (selectedIndex == -1 || selectedIndex > Application.Current.Resources.MergedDictionaries.Count - 1)
				{
					return false;
				}

				//Don't allow the user to delete resources that are not localizations.不允许用户删除非本地化的资源。
				if (Application.Current.Resources.MergedDictionaries[selectedIndex].Source?.OriginalString?.Contains("StringResources") != true)
				{
					return false;
				}

				//Remove from the current list.从当前列表中删除。
				Application.Current.Resources.MergedDictionaries.RemoveAt(selectedIndex);

				return true;
			}
			catch (Exception ex)
			{
				LogWriter.Log(ex, "Remove Resource", selectedIndex);
				return false;
			}
		}

		/// <summary>
		/// Gets a resource as string. 以字符串形式获取资源。
		/// </summary>
		/// <param name="key">The key of the string resource.字符串资源的键</param>
		/// <param name="removeNewLines">If true, it removes any kind of new lines.如果为true，则删除任何类型的新行。</param>
		/// <returns>A string resource, usually a localized string.字符串资源，通常是本地化字符串</returns>
		public static string Get(string key, bool removeNewLines = false)
		{
			return removeNewLines
				? (Application.Current.TryFindResource(key) as string ?? "").Replace("\n", " ").Replace("\\n", " ").Replace("\r", " ").Replace("&#10;", " ").Replace("&#x0d;", " ")
				: Application.Current.TryFindResource(key) as string;
		}

		/// <summary>
		/// Gets a resource as string and applies the format.获取字符串形式的资源并应用格式。
		/// </summary>
		/// <param name="key">The key of the string resource.</param>
		/// <param name="values">The values for the string format.</param>
		/// <returns>A string resource, usually a localized string.</returns>
		public static string GetWithFormat(string key, params object[] values)
		{
			return string.Format(CultureInfo.CurrentUICulture, Application.Current.TryFindResource(key) as string ?? "", values);
		}

		/// <summary>
		/// Gets a resource as string.以字符串形式获取资源。
		/// </summary>
		/// <param name="key">The key of the string resource.</param>
		/// <param name="defaultValue">The default value in english.</param>
		/// <param name="removeNewLines">If true, it removes any kind of new lines.</param>
		/// <returns>A string resource, usually a localized string.</returns>
		public static string Get(string key, string defaultValue, bool removeNewLines = false)
		{
			return removeNewLines
				? (Application.Current.TryFindResource(key) as string ?? defaultValue).Replace("\n", " ").Replace("\\n", " ").Replace("\r", " ").Replace("&#10;", " ").Replace("&#x0d;", " ")
				: Application.Current.TryFindResource(key) as string ?? defaultValue;
		}

		/// <summary>
		/// Gets a resource as string and applies the format.获取字符串形式的资源并应用格式。
		/// </summary>
		/// <param name="key">The key of the string resource.</param>
		/// <param name="defaultValue">The default value in english.</param>
		/// <param name="values">The values for the string format.</param>
		/// <returns>A string resource, usually a localized string.</returns>
		public static string GetWithFormat(string key, string defaultValue, params object[] values)
		{
			return string.Format(CultureInfo.CurrentUICulture, Application.Current.TryFindResource(key) as string ?? defaultValue, values);
		}

		/// <summary>
		/// Gets a resource as string.以字符串形式获取资源。
		/// </summary>
		/// <param name="index"></param>
		/// <param name="key">The key of the string resource.</param>
		/// <param name="values">The possible values that composite the key name.</param>
		/// <returns>A string resource, usually a localized string.</returns>
		public static string GetWithIndex(int index, string key, params string[] values)
		{
			return Application.Current.TryFindResource(key + values[index]) as string;
		}
	}
}
